package com.samuel.basics.shiro;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.samuel.basics.constant.CommonConstant;
import com.samuel.basics.entity.LoginLogEntity;
import com.samuel.basics.entity.MenuEntity;
import com.samuel.basics.entity.UserEntity;
import com.samuel.basics.mapper.RoleMapper;
import com.samuel.basics.mapper.UserMapper;
import com.samuel.basics.service.LoginLogService;
import com.samuel.basics.service.MenuService;
import com.samuel.basics.utils.BaseUtil;
import com.samuel.basics.utils.IpUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 用户实现shiro权限
 *
 * @author kaiji
 */
public class UserRealm extends AuthorizingRealm {

    private static final Logger logger = LoggerFactory.getLogger(UserRealm.class);

    @Resource
    private UserMapper userMapper;
    @Resource
    private RoleMapper roleMapper;
    @Resource
    private MenuService menuService;
    @Resource
    private LoginLogService loginLogService;

    /**
     * <p>
     * 检测登录信息
     * </p>
     * @param authenticationToken
     *  用户身份信息
     * @return  AuthenticationInfo 身份信息
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        logger.info("获取用户身份信息！");
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        UserEntity userEntity = userMapper.selectOne(new QueryWrapper<UserEntity>().eq("phone", token.getUsername()));
        if (null == userEntity) {
            throw new UnknownAccountException("用户名不正确！");
        } else if (!userEntity.getAuthCode().equals(new String((char[]) token.getCredentials()))) {
            throw new ExcessiveAttemptsException("验证码不正确");
        } else if (!userEntity.getStatus().equals(CommonConstant.MAGIC_VALUE_ZERO)) {
            throw new LockedAccountException("账户已经被锁定");
        }

        // 修改用户信息
        userEntity.setLoginIp(IpUtils.getIpFromRequest(BaseUtil.getHttpServletRequest()));
        userEntity.setLoginDate(LocalDateTime.now());
        userMapper.updateById(userEntity);

        // 记录登录日志
        LoginLogEntity loginLogEntity = new LoginLogEntity();
        loginLogEntity.setLoginName(userEntity.getUsername());
        loginLogEntity.setLogName("登录日志");
        loginLogEntity.setIp(userEntity.getLoginIp());
        loginLogEntity.setCreateDate(LocalDateTime.now());
        loginLogService.save(loginLogEntity);

        return new SimpleAuthenticationInfo(userEntity, userEntity.getAuthCode(), getName());
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        logger.info("————权限认证————");
        UserEntity userEntity = (UserEntity) SecurityUtils.getSubject().getPrincipal();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //获得该用户角色
        Set<String> roles = userMapper.getRoleByPhone(userEntity.getPhone());
        //设置该用户拥有的角色
        info.setRoles(roles);

        Set<String> urls;
        boolean match = roles.stream().anyMatch(role -> StringUtils.equals(CommonConstant.ADMIN, role));
        if (match) {
            logger.info("超级管理员闪亮登录");
            urls = menuService.list().stream().map(MenuEntity::getUrl).collect(Collectors.toSet());
        } else {
            // 获取这些角色所拥有URL
            List<String> codes = new ArrayList<>(roles);
            urls = roleMapper.getUrlByRole(codes);
        }
        info.setStringPermissions(urls);
        return info;
    }

}
